package pl.us.ij.plugins.segmentation.commands.filters;

import ij.process.FloatProcessor;
import pl.us.ij.plugins.segmentation.commands.MatrixHelper;
import pl.us.ij.plugins.segmentation.infrastructure.Command;
import pl.us.ij.plugins.segmentation.infrastructure.exceptions.BreakCommandException;

/**
 * Created by IntelliJ IDEA.
 * User: Przemek
 * Date: 2010-01-07
 * Time: 23:59:14
 * To change this template use File | Settings | File Templates.
 */
public class GaussFilterCommand extends Command<FilterCommandParams> {

//    @Override

    protected void process(FloatProcessor fp) {

        FilterCommandParams params = getParams();

        float[][] mask = MatrixHelper.floatOnes(3);
        mask = MatrixHelper.floatMatrix(3, 1, 2, 1, 2, 4, 2, 1, 2, 1);
        int width = fp.getWidth();
        int height = fp.getHeight();

        int iterationCount = params.getIterationCount();

        while (iterationCount-- > 0) {
            float[] pixels = (float[]) fp.getPixels();

            maskFilter(mask, width, height, pixels, true, 0, 255);

//            fp.setPixels(pixels);
        }

    }

    public static void maskFilter(float[][] mask, int width, int height, float[] inOutPixels, boolean replacePixels, float minValue, float maxValue) {

        float mask_sum = MatrixHelper.floatSum(mask);

        if (mask_sum == 0 || !replacePixels)
            mask_sum = 1;

        float[][] h = MatrixHelper.floatZeros(3);
        float[] pixels = inOutPixels.clone();

        for (int y = 1; y < height - 1; y++) {
            int shift0 = width * (y - 1);
            int shift1 = width * (y);
            int shift2 = width * (y + 1);

            int shiftD = width * y;

            for (int x = 1; x < width - 1; x++) {
                h[0][0] = (pixels[shift0 + (x - 1)]);
                h[0][1] = (pixels[shift0 + (x)]);
                h[0][2] = (pixels[shift0 + (x + 1)]);

                h[1][0] = (pixels[shift1 + (x - 1)]);
                h[1][1] = (pixels[shift1 + (x)]);
                h[1][2] = (pixels[shift1 + (x + 1)]);

                h[2][0] = (pixels[shift2 + (x - 1)]);
                h[2][1] = (pixels[shift2 + (x)]);
                h[2][2] = (pixels[shift2 + (x + 1)]);

                float[][] mh = MatrixHelper.floatMultiply(h, mask);

                float pixel = Math.round((MatrixHelper.floatSum(mh) / mask_sum));

                if (replacePixels)
                    inOutPixels[shiftD + x] = pixel;
                else {
                    if (inOutPixels[shiftD + x] + pixel > maxValue)
                        inOutPixels[shiftD + x] = maxValue;
                    else
                        inOutPixels[shiftD + x] += pixel;
                }
            }
        }
    }

    public static void maskFilter2(float[][] mask, int width, int height, float[] inOutPixels ) {

        float[][] h = MatrixHelper.floatZeros(3);
        float[] pixels = inOutPixels.clone();

        for (int y = 1; y < height - 1; y++) {
            int shift0 = width * (y - 1);
            int shift1 = width * (y);
            int shift2 = width * (y + 1);

            int shiftD = width * y;

            for (int x = 1; x < width - 1; x++) {
                h[0][0] = (pixels[shift0 + (x - 1)]);
                h[0][1] = (pixels[shift0 + (x)]);
                h[0][2] = (pixels[shift0 + (x + 1)]);

                h[1][0] = (pixels[shift1 + (x - 1)]);
                h[1][1] = (pixels[shift1 + (x)]);
                h[1][2] = (pixels[shift1 + (x + 1)]);

                h[2][0] = (pixels[shift2 + (x - 1)]);
                h[2][1] = (pixels[shift2 + (x)]);
                h[2][2] = (pixels[shift2 + (x + 1)]);

                float[][] mh = MatrixHelper.floatMultiply(h, mask);

                float pixel = MatrixHelper.floatSum(mh);

                inOutPixels[shiftD + x] = pixel;
            }
        }
    }

    @Override
    protected void processImage(FloatProcessor fp) throws BreakCommandException {
        process(fp);
    }
}

